﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Threading;
using System.Net;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization;
using System.IO;

namespace Snake.Model
{
   
        class Serveur
        {
            private Mutex mu = new Mutex();

            private TcpListener tcpListener;
            private TcpClient tcpClient;
           
            private Thread listenThread;
            private Thread clientThread;
            
            private snake snake;
            private snake snakeRecu;


            private byte[] message = new byte[4096];
           // private TcpClient client;
            private Boolean ClientConnected;
            private NetworkStream clientStream;
            private String NameOtherPlayer;

            public snake SnakeRecu
            {
                get { return this.snakeRecu; }
            }

            public Boolean clientconnected
            {
                get { return this.ClientConnected; }
                set { this.ClientConnected = value; }
            }

            public String nameotherplayer
            {
                get { return this.NameOtherPlayer; }
                set { this.NameOtherPlayer = value; }
            }

            public Serveur(snake snake)
            {
                this.snake = snake;
                this.tcpListener = new TcpListener(IPAddress.Any, 3000);//port d'écoute 3000
                //utiliser un thread pour envoyer
                this.listenThread = new Thread(new ThreadStart(ListenForClients));
                this.listenThread.Name = "Thread d'attente connexion";
                this.listenThread.Start();
            
            }


            private void ListenForClients()
            {
                this.tcpListener.Start();

                while (true)
                {
                    try
                    {
                        //blocks until a client has connected to the server
                        ClientConnected = false;
                        Console.WriteLine("Attend co");
                        TcpClient client = this.tcpListener.AcceptTcpClient();
                        Console.WriteLine("co");
                        //System.Windows.Forms.MessageBox.Show("Maintenant connexion effectué");
                        //create a thread to handle communication 
                        this.tcpClient = (TcpClient)client;
                        this.clientStream = tcpClient.GetStream();
                        //with connected client
                        //new ParameterizedThreadStart(
                        this.clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
                        this.clientThread.Name = "thread envoi et reception";
                        this.clientThread.Start(client);
                    }
                    catch (Exception)
                    {
                        Console.WriteLine("Erreur connexion Serveur - Client ");
                        this.EndServ();
                    }
                }
            }

            
            private void HandleClientComm(object client)
            {
                while (true)
                {
                    try
                    {
                        this.mu.WaitOne();
                        IFormatter formatter = new BinaryFormatter();

                        this.snakeRecu = (snake)formatter.Deserialize(clientStream);

                        this.NameOtherPlayer = this.snakeRecu.nameplayer;
                         Console.WriteLine("Nom recu = " + this.snakeRecu.nameplayer);
                         Console.WriteLine("Nom score = " + this.snakeRecu.Score);
                        ClientConnected = true;
                        //ne dois pas être fait tant que la connexion n'est pas réaliser ..

                        this.Envoi();
                        this.mu.ReleaseMutex();
                    }
                    catch (Exception)
                    {
                        Console.WriteLine("Erreur Reception du Client");
                        this.EndServ();
                    }
                }

                //tcpClient.Close();
            }

            private void Envoi()
            {
                try
                {
                    MemoryStream fs = new MemoryStream();

                    IFormatter formatter = new BinaryFormatter();
                    //probleme ici a gere quand on perds la connexion
                    //if (this.snake.Envoyer)
                    {
                        formatter.Serialize(this.clientStream, this.snake);
                    }
                }
                catch(Exception)
                {
                     Console.WriteLine("Erreur envoie vers Client");
                     this.EndServ();
                }
            }

            public void EndServ()
            {
                this.listenThread.Abort();
                this.clientThread.Abort();
                this.tcpListener.Stop();
                this.tcpClient.Close();
                this.clientStream.Close();
            }
        }
    
}
